package com.net.xpay.common.service.impl;

import com.net.xpay.common.domain.DailyTaskRecord;
import com.net.xpay.common.enums.systemTask.DailyTaskStatus;
import com.net.xpay.common.manager.DailyTaskRecordManager;
import com.net.common.util.NetUtil;
import com.net.xpay.common.service.DailyTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

/**
 * 处理按天任务的抽象服务类
 * Created by  on 2017/2/8.
 */
@Slf4j
public abstract class AbstractDailyTaskService implements DailyTaskService {


    @Autowired
    protected DailyTaskRecordManager dailyTaskRecordManager;

    @Override
    public void startDailyWork() {
        //先把手动的执行完，然后执行每天的例行任务
        String dailyTaskName = getDailyTaskName();
        log.warn("daily task start to work|name={}", dailyTaskName);
        long start = System.currentTimeMillis();
        doManualTask(dailyTaskName);

        doDailyTask(dailyTaskName);
        log.warn("daily task finish|name={}|time={}", dailyTaskName, System.currentTimeMillis() - start);
    }

    private void doManualTask(String dailyTaskName) {
        List<DailyTaskRecord> manualTask = dailyTaskRecordManager.listManualWaitTask(dailyTaskName);
        for (DailyTaskRecord record : manualTask) {
            doWorkByDay(dailyTaskName, record);
        }
    }

    private void doDailyTask(String dailyTaskName) {
        LocalDate day;
        DailyTaskRecord latestSuccessTask = dailyTaskRecordManager.getLatestSuccessTask(dailyTaskName);
        if (latestSuccessTask == null) {
            log.warn("daily task could not find last success task|task_name=" + dailyTaskName);
            day = LocalDate.now().minusDays(getFirstStartDayDiff());  //第一次从提前几天算起
        } else {
            day = latestSuccessTask.getDay().plusDays(1);
        }

        LocalDate today = LocalDate.now();
        if (!today.isAfter(day)) {
            log.warn("daily task no task to do |task={}|time={}", dailyTaskName, new Date());
            return;  //今天没有需要处理的任务
        }
        while (day.isBefore(today)) {
            DailyTaskRecord record = DailyTaskRecord.getInstance(dailyTaskName, day, 0, NetUtil.getHostIp());
            dailyTaskRecordManager.save(record);
            if (!doWorkByDay(dailyTaskName, record)) {
                log.error("daily task process task failed and exit|" + record.getId());
                break;
            }
            day = day.plusDays(1);
        }
    }

    private boolean doWorkByDay(String dailyTaskName, DailyTaskRecord record) {
        log.warn("daily task start to do work by day|taskName={}|day={}", dailyTaskName, record.getDay());
        List<DailyTaskRecord> unFinishedTaskList = dailyTaskRecordManager.getUnFinishedTask(dailyTaskName, record.getDay());
        for (DailyTaskRecord unFinish : unFinishedTaskList) {
            if (!unFinish.getId().equals(record.getId())) {
                unFinish.setTaskStatus(DailyTaskStatus.FAILED);
                dailyTaskRecordManager.update(unFinish); //将同一天其它的需要重置为失败了
            }
        }

        try {
            record.setStartTime(LocalDateTime.now());
            if (doWorkByDayInternal(record)) {
                record.setTaskStatus(DailyTaskStatus.SUCCESS);
            } else {
                record.setTaskStatus(DailyTaskStatus.FAILED);
            }
        } catch (Exception e) {
            log.error("daily task do work by day with exception|taskName={}|day={}", dailyTaskName, record.getDay(), e);
            record.setTaskStatus(DailyTaskStatus.FAILED);
        }
        record.setEndTime(LocalDateTime.now());
        dailyTaskRecordManager.update(record);
        log.warn("daily task finish do work by day|taskName={}|day={}", dailyTaskName, record.getDay());
        return DailyTaskStatus.SUCCESS.equals(record.getTaskStatus());
    }

    protected int getFirstStartDayDiff() {
        return 2; //提前几天计算,可以通过继承修改
    }

    protected abstract boolean doWorkByDayInternal(DailyTaskRecord record);

    protected abstract String getDailyTaskName();
}

